﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Threading;

namespace PBTService
{
    public class PaintballServer : IPaintballServer
    {
        private static bool IsServerAlive = true;

        private static Dictionary<PBTGamePlayer, IPaintballCallbackClient> Clients;
        private static PBTGamePlayer Host;
        private static PBTGamePlayer _Server;

        //Fields
        private Thread ProcessingThread;
        private static ConcurrentQueue<PBTServiceMessage> _ServerMessageQueue;
        
        //Construct
        public PaintballServer()
        {
            Clients = new Dictionary<PBTGamePlayer, IPaintballCallbackClient>();
            _Server = new PBTGamePlayer("SERVER");
        }

        //Methods        
        #region IPaintballServer Implementation  
      
        public void StartupServer(PBTGamePlayer host)
        {
            Host = host;
            Clients.Add(host, OperationContext.Current.GetCallbackChannel<IPaintballCallbackClient>());

            _ServerMessageQueue = new ConcurrentQueue<PBTServiceMessage>();
            ProcessingThread = new Thread(ProcessMessageQueue);
            ProcessingThread.Start();            
            Send(new PBTChatMessage(_Server, "New Client started ... host = " + host.Username));
        }
        public void Register(PBTGamePlayer client)
        {
            Clients.Add(client, OperationContext.Current.GetCallbackChannel<IPaintballCallbackClient>());
            Send(new PBTChatMessage(_Server, "New Client connected: " + client.Username));
        }
        public void Send(PBTServiceMessage message)
        {
            EnqueueServerMessage(message);
        }
        
        #endregion
        private void EnqueueServerMessage(PBTServiceMessage msg)
        {
            _ServerMessageQueue.Enqueue(msg);
        }
        private void ProcessMessageQueue(object obj)
        {
            while (IsServerAlive)
            {
                PBTServiceMessage toProccess = null;
                _ServerMessageQueue.TryDequeue(out toProccess);

                if (toProccess == null)
                    continue;

                //proccess the message
                if (toProccess is PBTUpdateMessage)
                {
                    //Redirect this message to all current clients
                    foreach (var client in Clients)
                    {
                        if ((client.Value as IContextChannel).State == CommunicationState.Opened)
                            client.Value.MessageReceived(toProccess);
                        else
                        {
                            //Potential Client Disconnect
                        }
                    }
                }
                else if (toProccess is PBTActionMessage)
                {
                    //Redirect this message to all current clients
                    foreach (var client in Clients)
                    {
                        if ((client.Value as IContextChannel).State == CommunicationState.Opened)
                            client.Value.MessageReceived(toProccess);
                        else
                        {
                            //Potential Client Disconnect
                        }
                    }
                }
                else if (toProccess is PBTChatMessage)
                {
                    //Send the Message off to all Listeners
                    foreach (var client in Clients)
                    {
                        if ((client.Value as IContextChannel).State == CommunicationState.Opened)
                            client.Value.MessageReceived(toProccess);
                        else
                        {
                            //Potential Client Disconnect
                        }
                    }
                }
                else
                    throw new FaultException("Unrecognised type");
            }
        }

    }
}
